﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using Facebook;
using WebApp.Models;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Text;
using System.IO;
using System.Collections.Specialized;
using System.Text.RegularExpressions;

namespace WebApp.Controllers
{
    [HandleError]
    public class ProfileController : ApplicationController
    {
        private const String URL_UPLOAD_PATH = "/Content/Upload/";
        private const String OS_UPLOAD_PATH = "\\Content\\Upload\\";

        /// <summary>
        /// Returns the result for the Index action
        /// </summary>
        /// <returns>The result for the Index action</returns>
        public ActionResult Index()
        {
            return Stream();
        }

        /// <summary>
        /// Returns the result for the Stream action
        /// </summary>
        /// <returns>The result for the Stream action</returns>
        public ActionResult Stream()
        {
            String authToken = HttpContext.Session["authToken"].ToString();
            List<Post> posts = Models.Post.PopulateList("me", authToken);

            foreach (Post.Ref postRef in posts)
            {
                postRef.Populate(authToken);
            }

            ViewData["TitleFragment"] = "Stream";
            ViewData["Model"] = posts;
            return View("Stream");
        }

        /// <summary>
        /// Returns the result for the Albums action
        /// </summary>
        /// <returns>The result for the Albums action</returns>
        public ActionResult Albums()
        {
            String authToken = HttpContext.Session["authToken"].ToString();
            List<Album> albums = Models.Album.PopulateList("me", authToken);
            // The cover images are just references. We need to populate each
            // of them so we can display a cover image
            foreach (Album album in albums)
            {
                album.Cover.Populate(authToken);
            }
            ViewData["TitleFragment"] = "Albums";
            ViewData["Model"] = albums;
            return View();
        }

        /// <summary>
        /// Returns the result for the Album action
        /// </summary>
        /// <returns>The result for the Album action</returns>
        public ActionResult Album()
        {
            String authToken = HttpContext.Session["authToken"].ToString();
            String albumId = RouteData.Values["id"].ToString();
            Album.Ref albumRef = new Album.Ref(albumId);
            albumRef.Populate(authToken);
            List<Photo> photos = albumRef.GetPhotosInAlbum(authToken);
            ViewData["TitleFragment"] = albumRef.Name;
            ViewData["Model"] = photos;
            ViewData["AlbumId"] = albumId;
            return View();
        }

        /// <summary>
        /// Returns the result for the Friends action
        /// </summary>
        /// <returns>The result for the Friends action</returns>
        public ActionResult Friends()
        {
            String authToken = HttpContext.Session["authToken"].ToString();

            List<Friends> friends = Models.Friends.getFriends("me", authToken);

            ViewData["TitleFragment"] = "Friends";
            ViewData["Model"] = friends;
            return View();
        }

        /// <summary>
        /// Returns the result for the Wall action
        /// </summary>
        /// <returns>The result for the Wall action</returns>
        public ActionResult Wall()
        {
            ViewData["TitleFragment"] = "Wall";
            return View();
        }

        /// <summary>
        /// Called before any of the actions are taken
        /// </summary>
        /// <param name="context"></param>
        override protected void OnActionExecuting(
            ActionExecutingContext context)
        {
            // If we don't have an auth token, we need to send the user to the
            // login page
            try
            {
                if (HttpContext.Session["authToken"] == null)
                {
                    context.Result = new RedirectResult("/");
                }
                String authToken = HttpContext.Session["authToken"].ToString();
                // Check if our auth token is still alive by trying to use it
                FacebookClient fbc = new FacebookClient(authToken);
                fbc.Get("me/albums");
            }
            catch (Exception e)
            {
                HttpContext.Session.Abandon();
                context.Result = new RedirectResult("/");
            }
            base.OnActionExecuting(context);
        }

        /// <summary>
        /// Uploads the image that was posted to this action
        /// </summary>
        /// <returns>The JSON expected by the jQuery uploader</returns>
        [HttpPost]
        public ActionResult Upload()
        {
            if (Request.Form["submit"] != null)
            {
                String albumId = Request.Form["AlbumId"];
                NameObjectCollectionBase.KeysCollection col = Request.Form.Keys;
                foreach (String key in col)
                {
                    Match match = Regex.Match(key, "file(\\d+)");
                    if (match.Success && match.Groups.Count == 2)
                    {
                        String id = match.Groups[1].Value;
                        String fileName = Request.Form[key];
                        String rootPath = Request.ServerVariables["APPL_PHYSICAL_PATH"] + OS_UPLOAD_PATH;
                        String caption = "";
                        if (Request.Form["photoCaption" + id] != null)
                        {
                            caption = Request.Form["photoCaption" + id];
                        }
                        UploadFile(fileName, rootPath, caption, albumId);
                    }
                }
                Response.Redirect(Url.Action("Album", "Profile", new { id = Request.Form["AlbumId"] }));
                return null;
            }
            else
            {
                HttpFileCollectionBase files = Request.Files;
                if (files.Count == 0)
                    return null;
                HttpPostedFileBase file = files[0];
                // Make sure it's an image
                if (!file.ContentType.StartsWith("image/") &&
                    (file.FileName.EndsWith(".jpg") || file.FileName.EndsWith(".jpeg") ||
                    file.FileName.EndsWith(".png") || file.FileName.EndsWith(".gif")))
                    return null;
                // Save and resize the image
                String rootPath = Request.ServerVariables["APPL_PHYSICAL_PATH"] + OS_UPLOAD_PATH;
                String fileName = rootPath + file.FileName;
                file.SaveAs(fileName);
                String thumbName = MakeThumbnail(rootPath, file.FileName);
                String urlPath = Request.Url.GetLeftPart(
                        UriPartial.Authority) + URL_UPLOAD_PATH;

                String json = new JavaScriptSerializer().Serialize(new object[] { new
                {
                    name = file.FileName,
                    type = file.ContentType,
                    size = file.ContentLength,
                    url = urlPath + file.FileName,
                    thumbnail_url = urlPath + thumbName
                } });
                ContentResult result = new ContentResult();
                result.Content = json;
                // IE will try to download our JSON if we send it with content
                // type application.
                result.ContentType = "text/plain";
                Response.ContentType = "text/plain";
                return result;
            }
        }

        /// <summary>
        /// Uploads the given file to facebook
        /// </summary>
        /// <param name="fileName">The name of the file in the filesystem</param>
        /// <param name="rootPath">The path of the file</param>
        /// <param name="caption">The caption to go with the image</param>
        /// <param name="albumId">The id of the album the photo goes in</param>
        private void UploadFile(String fileName, String rootPath, String caption,
            String albumId)
        {
            Match extMatch = Regex.Match(fileName, "\\.(jpe?g|png|gif)", RegexOptions.IgnoreCase);
            if (extMatch.Success && extMatch.Groups.Count > 1)
            {
                byte[] fileBytes = System.IO.File.ReadAllBytes(rootPath + fileName);
                System.IO.File.Delete(rootPath + fileName);
                String contentType = null;
                String ext = extMatch.Groups[1].Value;
                if (ext.Equals("jpg", StringComparison.CurrentCultureIgnoreCase) ||
                    ext.Equals("jpeg", StringComparison.CurrentCultureIgnoreCase))
                {
                    contentType = "image/jpeg";
                }
                else if (ext.Equals("png", StringComparison.CurrentCultureIgnoreCase))
                {
                    contentType = "image/png";
                }
                else if (ext.Equals("gif", StringComparison.CurrentCultureIgnoreCase))
                {
                    contentType = "image/gif";
                }
                if (contentType != null)
                {
                    FacebookMediaObject mediaObject = new FacebookMediaObject
                    {
                        FileName = URL_UPLOAD_PATH + fileName,
                        ContentType = "image/jpeg"
                    };
                    mediaObject.SetValue(fileBytes);
                    IDictionary<string, object> upload = new Dictionary<string, object>();
                    upload.Add("name", caption);
                    upload.Add("@file.jpg", mediaObject);
                    String authToken = HttpContext.Session["authToken"].ToString();
                    FacebookClient fbc = new FacebookClient(authToken);
                    fbc.Post("/" + albumId + "/photos", upload);
                }
            }
        }

        /// <summary>
        /// Creates a thumbnail of an image file in the same directory.
        /// </summary>
        /// <param name="path">The path of the original image</param>
        /// <param name="filename">The filename of the original image</param>
        /// <returns>The filename of the new thumbnail</returns>
        private String MakeThumbnail(String path, String filename)
        {
            // Largest dimension
            double thumbSize = 130.0;
            StringBuilder thumbName = new StringBuilder(filename);
            thumbName.Replace('.', '_');
            thumbName.Append("_thumb.png");

            Image img = Image.FromFile(path + filename);

            // Scale the thumbnail
            int newWidth, newHeight;
            if (img.Height >= img.Width)
            {
                newHeight = (int)thumbSize;
                newWidth = (int)(img.Width * thumbSize / img.Height);
            }
            else
            {
                newWidth = (int)thumbSize;
                newHeight = (int)(img.Height * thumbSize / img.Width);
            }

            Image thumb = img.GetThumbnailImage(newWidth, newHeight, null,
            (IntPtr)null);
            thumb.Save(path + thumbName.ToString(), ImageFormat.Png);
            img.Dispose();
            thumb.Dispose();
            return thumbName.ToString();
        }
    }
}
